﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using LineEditTest;
using PSLib.CodeFormating.Lexems;
using System.Windows.Controls.Primitives;

namespace StudioEditorTest.CodeEditor
{
	/// <summary>
	/// Interaction logic for CodeLinePresenter.xaml
	/// </summary>
	public partial class CodeLinePresenter : UserControl
	{
		// Using a DependencyProperty as the backing store for FocusedCodeBlock.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty FocusedCodeBlockProperty =
			DependencyProperty.Register("FocusedCodeBlock", typeof(CodeBlockPresenter), typeof(CodeBlockPresenter), new UIPropertyMetadata(null));


		public CodeLinePresenter()
		{
			InitializeComponent();
			this.codeBlockIndex2Select = null;
			this.changing = false;

			this.listView.ItemContainerGenerator.ItemsChanged += new System.Windows.Controls.Primitives.ItemsChangedEventHandler(ItemContainerGenerator_ItemsChanged);
			this.listView.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
		}

		void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
		{
			GeneratorStatus status = this.listView.ItemContainerGenerator.Status;
			if (status == GeneratorStatus.ContainersGenerated)
			{
				changing = false;
				if (this.codeBlockIndex2Select.HasValue)
				{
					listView.SelectedIndex = this.codeBlockIndex2Select.Value;
					this.codeBlockIndex2Select = null;
				}
			}
		}

		void ItemContainerGenerator_ItemsChanged(object sender, System.Windows.Controls.Primitives.ItemsChangedEventArgs e)
		{
			this.changing = true;
		}

		private void UserControl_Loaded(object sender, RoutedEventArgs e)
		{
		}

		protected override void OnPreviewKeyDown(KeyEventArgs e)
		{
			CodeLine cl = this.CodeLine;
			if (cl != null)
			{
			    if (cl.CodeBlocks.Count == 0) cl.CodeBlocks.Add(new CodeBlock());
				if (listView.SelectedIndex == -1) FocusCodeBlock(0);
			}

			if (!e.Handled && this.FocusedCodeBlock != null)
			{
				this.FocusedCodeBlock.ProcessKeyDown(e);
			}
			base.OnPreviewKeyDown(e);
		}

		internal void ReportLexemInconsistency(CodeBlockPresenter codeBlockPresenter,CodeBlockLexemInconsistencyArgs e)
		{
			DependencyObject lvi = codeBlockPresenter.ListViewItem;
			switch (e.Type)
			{
				case LexemInconsistencyType.Empty:
					//if (listView.Items.Count != 1)
					//{
					//    this.CodeLine.CodeBlocks.Remove(codeBlockPresenter.CodeBlock);
					//    if (index == 0) FocusCodeBlock(index);
					//    else FocusCodeBlock(index - 1);
					//}
					break;
				case LexemInconsistencyType.Splitted:

					int absolutePos = GetAbsolutePosition(codeBlockPresenter.CodeBlock);

					string sourceWithNeighbours = string.Empty;
					CodeBlockPresenter prev = codeBlockPresenter.PrevBlockPresenter;
					if (prev != null) sourceWithNeighbours += prev.CodeBlock.Source;

					sourceWithNeighbours += codeBlockPresenter.CodeBlock.Source;

					CodeBlockPresenter next = codeBlockPresenter.NextBlockPresenter;
					if (next != null) sourceWithNeighbours += next.CodeBlock.Source;

					LexemList ll = ParseManager.Current.ParseSource(sourceWithNeighbours, false);

					if (prev != null)
					{
						prev.CodeBlock.Source = ll[0].LexemSource;
						ll.RemoveAt(0);
					}
					if (next != null)
					{
						next.CodeBlock.Source = ll[ll.Count - 1].LexemSource;
						ll.RemoveAt(ll.Count - 1);
					}

					if (ll.Count == 0) this.CodeLine.CodeBlocks.Remove(codeBlockPresenter.CodeBlock);
					else
					{
						codeBlockPresenter.CodeBlock.SetValue(CodeBlockPresenter.CursorPositionProperty, -1);
						codeBlockPresenter.CodeBlock.Source = ll[0].LexemSource;
						
						ll.RemoveAt(0);
						int index = this.CodeLine.CodeBlocks.IndexOf(codeBlockPresenter.CodeBlock);
						foreach (var item in ll)
						{
							index++;
							this.CodeLine.CodeBlocks.Insert(index, new CodeBlock { Source = item.LexemSource });
						}
					}

					SetAbsolutePosition(absolutePos);
					
					break;
				default:
					break;
			}
		}

		public CodeLine CodeLine
		{
			get { return this.DataContext as CodeLine; }
		}

		public CodeBlockPresenter FocusedCodeBlock
		{
			get { return (CodeBlockPresenter)GetValue(FocusedCodeBlockProperty); }
			set { SetValue(FocusedCodeBlockProperty, value); }
		}

		public ItemContainerGenerator ItemContainerGenerator
		{
			get { return listView.ItemContainerGenerator; }
		}
		

		private void FocusCodeBlock(int index)
		{
			if (changing) codeBlockIndex2Select = index;
			else this.listView.SelectedIndex = index;
		}

		private void listView_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			if (this.listView.SelectedIndex != -1)
			{
				ListViewItem lvi = listView.ItemContainerGenerator.ContainerFromIndex(this.listView.SelectedIndex) as ListViewItem;
				CodeBlockPresenter cbPresenter = UITools.FindVisualChild<CodeBlockPresenter>(lvi);
				this.FocusedCodeBlock = cbPresenter;
			}
		}

		public int GetAbsolutePosition(CodeBlock block)
		{
			int position = 0;
			foreach (var item in this.CodeLine.CodeBlocks)
			{
				if (item == block) 
				{
					position += (int)block.GetValue(CodeBlockPresenter.CursorPositionProperty);
					return position;
				}
				position += item.Source.Length;
			}
			return 0;
		}

		public void SetAbsolutePosition(int pos)
		{
			foreach (var item in this.CodeLine.CodeBlocks)
			{
				item.SetValue(CodeBlockPresenter.CursorPositionProperty, -1);
				if (pos != -1)
				{
					if (pos - item.Source.Length <= 0)
					{
						item.SetValue(CodeBlockPresenter.CursorPositionProperty, pos);
						pos = -1;
					}
					else
					{
						pos -= item.Source.Length;
					}
				}
			}
		}

		private int? codeBlockIndex2Select;
		private bool changing;
	}
}
